package com.gome.ocean.service.task;

import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.mail.MessagingException;

import org.apache.commons.lang3.StringUtils;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidPooledConnection;
import com.alibaba.druid.pool.ValidConnectionChecker;
import com.alibaba.druid.pool.vendor.MySqlValidConnectionChecker;
import com.alibaba.druid.pool.vendor.OracleValidConnectionChecker;
import com.alibaba.druid.util.JdbcUtils;
import com.gome.ocean.common.enums.DataBaseType;
import com.gome.ocean.common.enums.DataSourceStatus;
import com.gome.ocean.common.utils.SpringContextUtil;
import com.gome.ocean.common.utils.TimeUtils;
import com.gome.ocean.dao.model.authority.ProjectBO;
import com.gome.ocean.dao.model.gddl.AppBO;
import com.gome.ocean.dao.model.gddl.AppDatasourceBO;
import com.gome.ocean.service.authority.ProjectService;
import com.gome.ocean.service.gddl.AppDatasourceService;
import com.gome.ocean.service.gddl.AppService;
import com.gome.ocean.service.mail.EmailConstants;
import com.gome.ocean.service.mail.EmailSubject;
import com.gome.ocean.service.mail.SimpleMailSender;
import com.gome.ocean.service.scheduler.SchedulerServiceBean;
import com.taobao.tddl.atom.common.TAtomConstants;

/**
 * 检测数据源后台任务
 * 
 * @author haqiaolong 2016年4月14日 下午5:30:26
 * @since 5.0.0
 */
public class CheckDataSourceJobTask extends ScheduledJobTask {

    private static final Logger  LOG                       = LoggerFactory.getLogger(CheckDataSourceJobTask.class);
    private static final int     DEAULT_QUERY_TIMEOUT_TIME = 5000;                                                 // 查询超时时间

    private AppService appService;
    private ProjectService       projectService;
    private AppDatasourceService appDatasourceService;
    private SimpleMailSender     simpleMailSender;
    private SchedulerServiceBean schedulerServiceBean;

    @Override
    public boolean checkTask() throws JobExecutionException {
        return true;
    }

    @Override
    public void initTask() throws JobExecutionException {
        if (this.appService == null) this.appService = SpringContextUtil.getBean("appService");
        if (this.projectService == null) this.projectService = SpringContextUtil.getBean("projectService");
        if (this.appDatasourceService == null) this.appDatasourceService = SpringContextUtil.getBean("appDatasourceService");
        if (this.simpleMailSender == null) this.simpleMailSender = SpringContextUtil.getBean("simpleMailSender");
        if (this.schedulerServiceBean == null) this.schedulerServiceBean = SpringContextUtil.getBean("schedulerServiceBean");
    }

    @Override
    public void runTask() throws JobExecutionException {
        Map<Long, DataSourceWrapper> allDataSources = LoadDatasourceJobTask.getAppDataSources();
        for (Entry<Long, DataSourceWrapper> datasource : allDataSources.entrySet()) {
            try {
                DataSourceWrapper dataSourceWrapper = datasource.getValue();
                DruidDataSource localDruidDataSource = dataSourceWrapper.getDruidDataSource();
                boolean isValid = false;
                if (localDruidDataSource.getDbType().equals(DataBaseType.MySql.getTypeFullName())) {
                    ValidConnectionChecker mysqlvalid = new MySqlValidConnectionChecker();
                    DruidPooledConnection connection = localDruidDataSource.getConnection();
                    try {
                        isValid = mysqlvalid.isValidConnection(connection,
                            TAtomConstants.DEFAULT_DRUID_MYSQL_VALIDATION_QUERY,
                            DEAULT_QUERY_TIMEOUT_TIME);
                    } finally {
                        JdbcUtils.close(connection);
                    }
                } else {
                    DruidPooledConnection connection = localDruidDataSource.getConnection();
                    try {
                        ValidConnectionChecker oracleValid = new OracleValidConnectionChecker();
                        isValid = oracleValid.isValidConnection(localDruidDataSource.getConnection(),
                            TAtomConstants.DEFAULT_DRUID_ORACLE_VALIDATION_QUERY,
                            DEAULT_QUERY_TIMEOUT_TIME);
                    } finally {
                        JdbcUtils.close(connection);
                    }
                }
                if (isValid) {
                    AppDatasourceBO appDatasourceBO = appDatasourceService.findAppDatasourceBOById(datasource.getKey());
                    if (DataSourceStatus.SUCCESS == DataSourceStatus.getDataSourceStatus(Integer.valueOf(appDatasourceBO.getSourceStatus()))) {
                        continue;
                    } else {
                        appDatasourceBO.setSourceStatus(DataSourceStatus.SUCCESS.getValue());
                        appDatasourceService.updateAppDatasourceBOById(appDatasourceBO);
                    }
                } else {
                    AppDatasourceBO appDatasourceBO = appDatasourceService.findAppDatasourceBOById(datasource.getKey());
                    appDatasourceBO.setSourceStatus(DataSourceStatus.ERROR.getValue());
                    appDatasourceService.updateAppDatasourceBOById(appDatasourceBO);
                    LoadDatasourceJobTask.removeDataSource(appDatasourceBO.getId());
                    sendAlertMail(appDatasourceBO);
                    LOG.info("check app datasource status is error! dbname=" + appDatasourceBO.getDbName());
                }
            } catch (SQLException e) {
                LOG.error("chek datasource is error !" + e);
                AppDatasourceBO appDatasourceBO = appDatasourceService.findAppDatasourceBOById(datasource.getKey());
                appDatasourceBO.setSourceStatus(DataSourceStatus.ERROR.getValue());
                appDatasourceService.updateAppDatasourceBOById(appDatasourceBO);
                LoadDatasourceJobTask.removeDataSource(appDatasourceBO.getId());
                LOG.info("check app datasource status is error! dbname=" + appDatasourceBO.getDbName());
            }
        }
        LOG.info("check app datasource status is complate!!! appid=" + allDataSources.keySet());
    }

    /**
     * 发送报警邮件
     * 
     * @param appDatasourceBO
     */
    private void sendAlertMail(AppDatasourceBO appDatasourceBO) {
        try {
            AppBO appBO = appService.findAppBOById(appDatasourceBO.getAppId());
            if (appBO != null) {
                ProjectBO projectBO = projectService.findProjectByName(appBO.getProject());
                List<String> cc = null;
                if (projectBO != null && StringUtils.isNotEmpty(projectBO.getProjectEmail())) {
                    cc = Arrays.asList(StringUtils.split(projectBO.getProjectEmail(), ","));
                } else {
                    cc = simpleMailSender.getDefaultMail();
                }
                Map<String, String> contextMaps = new HashMap<String, String>();
                contextMaps.put("APPNAME", appBO.getAppName());
                contextMaps.put("DBNAME", appDatasourceBO.getDbName());
                contextMaps.put("DATE", TimeUtils.timestampToToday());
                contextMaps.put("ALERTCONTEXT", "检测到:[" + appDatasourceBO.getJdbcUrl() + "]假死现象!");
                contextMaps.put("PROJECT", EmailConstants.DEFAULT_PROJECT);
                simpleMailSender.send(cc, EmailSubject.SUSPEND, contextMaps);
            }
        } catch (MessagingException e) {
            LOG.error("send alert mail is error! " + e);
        }
    }
}
